package com.huidu.bitrade.listener;

import cn.hutool.core.util.RandomUtil;
import com.huidu.bitrade.vendor.provider.SMSProvider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
@Slf4j
public class ServerStateListener {


    private final SMSProvider smsProvider;
    private Map<String,String> monitorMap;//key:服务value：uri
    private List<String> notifyList;//发送短信手机号

    @Value("${server.monitor.host}")
    private String monitorHost;

    @Value("${server.monitor.flag}")
    private Integer flag;


    /**
     * 发送下线通知
     * @param param
     * @param notifyList
     * @throws Exception
     */
    private void sendCancelSms(List<String> param,List<String> notifyList){
        for (String phone : notifyList) {
            sendSms(param, phone, 8);
        }
    }

    /**
     * 发送上线通知
     * @param param
     * @param notifyList
     * @throws Exception
     */
    private void onlineEmail(List<String> param,List<String> notifyList) {
        for (String phone : notifyList) {
            sendSms(param, phone, 9);
        }
    }

    @Async
    public void sendSms(List<String> param,String phone, Integer type) {
        if(flag==0){
            log.info("=====服务状态监控发送短信未开启======");
            return;
        }
        try {
            smsProvider.sendMessageByTempId(phone,param,type);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private final Map<String, Integer> errorCountMap = new HashMap<>();
    private final Map<String, Boolean> isOfflineMap = new HashMap<>();
    @Scheduled(fixedRate = 20 * 1000) // 每20秒执行一次
    public void checkServiceStatus() {
        if(flag==0){
            log.info("=====服务状态监控发送短信未开启======");
            return;
        }
        for(String key:monitorMap.keySet()){
            int statusCode;
            String url = monitorMap.get(key);
            try {
                // 发送HTTP请求并获取响应码
                statusCode = sendHttpRequest(url);
                // 检查响应码
                if (statusCode == 500 || statusCode == 502 || statusCode == 504 ) {
                    checkCancel(url,key);
                } else {
                    // 响应码不为500或502，重置计数值为0
                    errorCountMap.put(url, 0);
                    Boolean isOffline = isOfflineMap.getOrDefault(url, false);
                    if (isOffline) {
                        String msg = "服务 " + key + " 检测正常"+RandomUtil.randomString(3);
                        onlineEmail(Collections.singletonList(msg), notifyList); // 发送短信上线通知
                        isOfflineMap.put(url, false);
                    }
                }
            } catch (IOException e) {
                checkCancel(url,key);
            }
        }
    }

    private void checkCancel(String url,String serverName) {
        //这里键值对无值时默认给0
        int count = errorCountMap.getOrDefault(url, 0);
        count++;
        errorCountMap.put(url, count);
        if (count >= 3) {
            String msg = "服务 " + serverName + " 连续异常 " + count + " 次"+ RandomUtil.randomString(3);
            sendCancelSms(Collections.singletonList(msg),notifyList); // 发送短信下线通知
            errorCountMap.put(url, 0); // 重置计数值为0
            isOfflineMap.put(url, true);
        }
    }

    private int sendHttpRequest(String url) throws IOException {
        HttpClient client = HttpClientBuilder.create().build();
        HttpGet request = new HttpGet(url);
        HttpResponse response = client.execute(request);
        return response.getStatusLine().getStatusCode();
    }

    @Value("#{'${server.monitor.uri:}'.split(',')}")
    public void setMonitorList(List<String> monitorList) {
        this.monitorMap = monitorList.stream().collect(Collectors.toMap(uri -> uri, uri -> monitorHost + uri));
    }

    @Value("#{'${server.monitor.notify:}'.split(',')}")
    public void setNotifyList(List<String> notifyList) {
        this.notifyList = notifyList;
    }
}
